home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / DJLGR106.ARJ / REGION.CC < prev    next >
C/C++ Source or Header  |  1992-03-29  |  12KB  |  566 lines

  1. /* This is file REGION.CC */
  2. /*
  3. ** Copyright (C) 1991 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954
  4. **
  5. ** This file is distributed under the terms listed in the document
  6. ** "copying.dj", available from DJ Delorie at the address above.
  7. ** A copy of "copying.dj" should accompany this file; if not, a copy
  8. ** should be available from where this file was obtained.  This file
  9. ** may not be distributed without a verbatim copy of "copying.dj".
  10. **
  11. ** This file is distributed WITHOUT ANY WARRANTY; without even the implied
  12. ** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. */
  14.  
  15. /* History:251,33 */
  16. #include <std.h>
  17. #include <sys/registers.h>
  18. #include "graphics.h"
  19.  
  20. static GrRegion *screen_region = 0;
  21. extern int _GrCurMode;
  22.  
  23. static void SetModeHook()
  24. {
  25.   screen_region->width = GrSizeX();
  26.   screen_region->height = GrSizeY();
  27.   screen_region->row_scale = GrSizeX();
  28.   screen_region->data = (unsigned char *)0xd0000000;
  29.   screen_region->rdata = (unsigned char *)0xd0100000;
  30.   screen_region->wdata = (unsigned char *)0xd0200000;
  31. }
  32.  
  33. extern int _GrSetModeHook;
  34.  
  35.  
  36. GrRegion *GrScreenRegion()
  37. {
  38.   if (_GrCurMode < GR_320_200_graphics)
  39.     GrSetMode(GR_default_graphics);
  40.   if (!screen_region)
  41.     screen_region = new GrRegion();
  42.   _GrSetModeHook = (int)SetModeHook;
  43.   SetModeHook();
  44.   return screen_region;
  45. }
  46.  
  47. GrRegion::GrRegion()
  48. {
  49.   flags = width = height = row_scale = 0;
  50.   rdata = wdata = data = 0;
  51.   parent = 0;
  52.   rel_x = rel_y = abs_x = abs_y = 0;
  53.   color = GrWhite();
  54. }
  55.  
  56. GrRegion::GrRegion(int w, int h)
  57. {
  58.   flags = 1;
  59.   rdata = wdata = data = (unsigned char *)malloc(w*h);
  60.   bzero(data,w*h);
  61.   width = w;
  62.   height = h;
  63.   row_scale = w;
  64.   color = GrWhite();
  65.   parent = 0;
  66.   rel_x = rel_y = abs_x = abs_y = 0;
  67. }
  68.  
  69. GrRegion::~GrRegion()
  70. {
  71.   if (flags && data)
  72.     free(data);
  73. }
  74.  
  75. GrRegion *GrRegion::SubRegion(int x, int y, int w, int h)
  76. {
  77.   if (!data) return 0;
  78.   GrRegion *tmp = new GrRegion();
  79.   if (!tmp) return 0;
  80.   if ((x < 0) || (y < 0))
  81.     return tmp;
  82.   if ((x >= width) || (y >= height))
  83.     return tmp;
  84.   if (x+w > width)
  85.     w = width - x;
  86.   if (y+h > height)
  87.     h = height - y;
  88.   tmp->parent = this;
  89.   tmp->rel_x = x;
  90.   tmp->rel_y = y;
  91.   tmp->abs_x = x + rel_x;
  92.   tmp->abs_y = y + rel_y;
  93.   tmp->data = data + y*row_scale + x;
  94.   tmp->rdata = rdata + y*row_scale + x;
  95.   tmp->wdata = wdata + y*row_scale + x;
  96.   tmp->width = w;
  97.   tmp->height = h;
  98.   tmp->row_scale = row_scale;
  99.   return tmp;
  100. }
  101.  
  102. int GrRegion::MaxX()
  103. {
  104.   return width-1;
  105. }
  106.  
  107. int GrRegion::MaxY()
  108. {
  109.   return height-1;
  110. }
  111.  
  112. int GrRegion::SizeX()
  113. {
  114.   return width;
  115. }
  116.  
  117. int GrRegion::SizeY()
  118. {
  119.   return height;
  120. }
  121.  
  122. void GrRegion::Plot(int x, int y, int c)
  123. {
  124.   if (!data) return;
  125.   if (c == -1) c = color;
  126.   if ((x < 0) || (y < 0) || (x >= width) || (y >= height))
  127.     return;
  128.   if (c & 0x100)
  129.     data[x+y*row_scale] ^= c;
  130.   else
  131.     data[x+y*row_scale] = c;
  132. }
  133.  
  134. /** Test a single point to be within the xleft,xright,ybot,ytop bbox.
  135.  ** Sets the returned integers 4 l.s.b. as follows:
  136.  ** bit 0 if to the left of xleft.
  137.  ** bit 1 if to the right of xright.
  138.  ** bit 2 if above of ytop.
  139.  ** bit 3 if below of ybot.
  140.  ** 0 is returned if inside.
  141.  */
  142. static inline int clipPoint(int x, int y, int width, int height)
  143. {
  144.   int ret_val = 0;
  145.  
  146.   if (x < 0) ret_val |= 0x01;
  147.   if (x > width) ret_val |= 0x02;
  148.   if (y < 0) ret_val |= 0x04;
  149.   if (y > height) ret_val |= 0x08;
  150.  
  151.   return ret_val;
  152. }
  153.  
  154. /**
  155.  ** Draw a line assumed to be clipped with respect to current region.
  156.  **/
  157. static void drawClippedLine(GrRegion *Region,
  158.                 int x1, int y1, int x2, int y2, int c)
  159. {
  160.   unsigned char *d = &Region->data[x1+y1*Region->row_scale];
  161.  
  162.   if (c == -1) c = Region->color;
  163.  
  164.   if (x1 == x2)
  165.   {
  166.     Region->VLine(x1, y1, y2, c);
  167.     return;
  168.   }
  169.   if (y1 == y2)
  170.   {
  171.     Region->HLine(x1, x2, y1, c);
  172.     return;
  173.   }
  174.  
  175.   int dx, dy, sx, sy;
  176.   int count;
  177.   int brc, brmax;
  178.  
  179.   sx = 1;
  180.   sy = Region->row_scale;
  181.   dx = x2 - x1;
  182.   dy = y2 - y1;
  183.   if (dx < 0)
  184.   {
  185.     dx = -dx;
  186.     sx = -sx;
  187.   }
  188.   if (dy < 0)
  189.   {
  190.     dy = -dy;
  191.     sy = -sy;
  192.   }
  193.  
  194.   if (c & 0x100)
  195.     *d ^= c;
  196.   else
  197.     *d = c;
  198.  
  199.   if (dx > dy)
  200.   {
  201.     brmax = dx;
  202.     brc = dx / 2;
  203.  
  204.     for (count = dx; count; count--)
  205.     {
  206.       d += sx;
  207.       brc += dy;
  208.       if (brc > brmax)
  209.       {
  210.         brc -= dx;
  211.         d += sy;
  212.       }
  213.  
  214.       if (c & 0x100)
  215.         *d ^= c;
  216.       else
  217.         *d = c;
  218.     }
  219.   }
  220.   else
  221.   {
  222.     brmax = dy;
  223.     brc = dy / 2;
  224.  
  225.     for (count = dy; count; count--)
  226.     {
  227.       d += sy;
  228.       brc += dx;
  229.       if (brc > brmax)
  230.       {
  231.         brc -= dy;
  232.         d += sx;
  233.       }
  234.  
  235.       if (c & 0x100)
  236.         *d ^= c;
  237.       else
  238.         *d = c;
  239.     }
  240.   }
  241. }
  242.  
  243. static inline int min(int x1, int x2)
  244. {
  245.   return x1 < x2 ? x1 : x2;
  246. }
  247.  
  248. static inline int max(int x1, int x2)
  249. {
  250.   return x1 > x2 ? x1 : x2;
  251. }
  252.  
  253. /** Clip and draw the given line to viewport defined using clipX/Y/min/max.
  254.  **   This routine uses the cohen & sutherland bit mapping for fast clipping -
  255.  ** see "Principles of Interactive Computer Graphics" Newman & Sproull page 65.
  256.  */
  257. static void clipLine(GrRegion *Region, int x1, int y1, int x2, int y2, int c)
  258. {
  259.   int x, y, x_intr[4], y_intr[4], count, pos1, pos2,
  260.     width = Region->width - 1,
  261.     height = Region->height - 1;
  262.   long dx, dy;
  263.  
  264.   pos1 = clipPoint(x1, y1, width, height);
  265.   pos2 = clipPoint(x2, y2, width, height);
  266.  
  267.   if (pos1 || pos2) {
  268.     int x_max, x_min, y_max, y_min;
  269.  
  270.     if (pos1 & pos2) return;          /* segment is totally out. */
  271.  
  272.     x_min = min(x1, x2);
  273.     x_max = max(x1, x2);
  274.     y_min = min(y1, y2);
  275.     y_max = max(y1, y2);
  276.  
  277.     /* Compute a bound on extrema of clipped line. */
  278.     x_min = max(x_min, 0);
  279.     x_max = min(x_max, width);
  280.     y_min = max(y_min, 0);
  281.     y_max = min(y_max, height);
  282.  
  283.     /* Here part of the segment MAY be inside. test the intersection
  284.      * of this segment with the 4 boundaries for hopefully 2 intersections
  285.      * in. If non found segment is totaly out.
  286.      */
  287.     count = 0;
  288.     dx = (long) (x2 - x1);
  289.     dy = (long) (y2 - y1);
  290.  
  291.     /* Find intersections with the x parallel bbox lines: */
  292.     if (dy != 0) {
  293.       if (0 == y_min) {                    /* Test clipYmin boundary. */
  294.     x = (int) (-y2 * dx / dy + x2);
  295.  
  296.     if (x >= x_min && x <= x_max) {
  297.       x_intr[count] = x;
  298.       y_intr[count++] = 0;
  299.         }
  300.       }
  301.       if (height == y_max) {            /* Test clipYmax boundary. */
  302.     x = (int) ((height - y2) * dx / dy + x2);
  303.  
  304.     if (x >= x_min && x <= x_max) {
  305.       x_intr[count] = x;
  306.       y_intr[count++] = height;
  307.     }
  308.       }
  309.     }
  310.  
  311.     /* Find intersections with the y parallel bbox lines: */
  312.     if (dx != 0) {
  313.       if (0 == x_min) {                    /* Test clipXmin boundary. */
  314.     y = (int) (-x2 * dy / dx + y2);
  315.  
  316.     if (y >= y_min && y <= y_max) {
  317.       x_intr[count] = 0;
  318.       y_intr[count++] = y;
  319.     }
  320.       }
  321.       if (width == x_max) {            /* Test clipXmax boundary. */
  322.     y = (int) ((width - x2) * dy / dx + y2);
  323.  
  324.     if (y >= y_min && y <= y_max) {
  325.       x_intr[count] = width;
  326.       y_intr[count++] = y;
  327.     }
  328.       }
  329.     }
  330.  
  331.     if (count >= 2) {
  332.       if (pos1 && pos2) {                   /* Both were out - update both. */
  333.     x1 = x_intr[0];
  334.     y1 = y_intr[0];
  335.     x2 = x_intr[1];
  336.     y2 = y_intr[1];
  337.       }
  338.       else if (pos1) {           /* Only x1/y1 was out - update only it. */
  339.     if (dx * (x2 - x_intr[0]) + dy * (y2 - y_intr[0]) > 0) {
  340.       x1 = x_intr[0];
  341.       y1 = y_intr[0];
  342.     }
  343.     else {
  344.       x1 = x_intr[1];
  345.       y1 = y_intr[1];
  346.     }
  347.       }
  348.       else {                      /* Only x2/y2 was out - update only it. */
  349.     if (dx * (x_intr[0] - x1) + dy * (y_intr[0] - x1) > 0) {
  350.       x2 = x_intr[0];
  351.       y2 = y_intr[0];
  352.     }
  353.         else {
  354.       x2 = x_intr[1];
  355.       y2 = y_intr[1];
  356.     }
  357.       }
  358.     }
  359.     else if (count == 1) {
  360.       if (pos1) {               /* Only x1/y1 was out - update only it. */
  361.     x1 = x_intr[0];
  362.     y1 = y_intr[0];
  363.       }
  364.       else {                      /* Only x2/y2 was out - update only it. */
  365.     x2 = x_intr[0];
  366.     y2 = y_intr[0];
  367.       }
  368.     }
  369.     else {            /* Count = 0 which means the lines is totally out. */
  370.       return;
  371.     }
  372.  
  373.     if (x1 < x_min || x1 > x_max ||
  374.         x2 < x_min || x2 > x_max ||
  375.     y1 < y_min || y1 > y_max ||
  376.     y2 < y_min || y2 > y_max) {
  377.       /* This is extreme and rare case in which integer round off causes */
  378.       /* no trimming in one direction.                         */
  379.  
  380.       /* Eliminate the trivial cases in which the line end point is on   */
  381.       /* the viewport boundary and the line is totally out.             */
  382.       if ((x1 <= x_min && x2 <= x_min) ||
  383.       (x1 >= x_max && x2 >= x_max) ||
  384.       (y1 <= y_min && y2 <= y_min) ||
  385.       (y1 >= y_max && y2 >= y_max))
  386.     return;
  387.  
  388.       /* Otherwise try to clip again... */
  389.       clipLine(Region, x1, y1, x2, y2, c);
  390.       return;
  391.     }
  392.   }
  393.  
  394.   drawClippedLine(Region, x1, y1, x2, y2, c);
  395. }
  396.  
  397. void GrRegion::Line(int x1, int y1, int x2, int y2, int c)
  398. {
  399.   if (!data) return;
  400.   if (c == -1) c = color;
  401.  
  402.   if (x1 == x2)
  403.     VLine(x1, y1, y2, c);
  404.   else if (y1 == y2)
  405.     HLine(x1, x2, y1, c);
  406.   else
  407.     clipLine(this, x1, y1, x2, y2, c);
  408. }
  409.  
  410. void GrRegion::HLine(int x1, int x2, int y, int c)
  411. {
  412.   if (!data) return;
  413.   if (c == -1) c = color;
  414.   if ((y < 0) || (y >= height))
  415.     return;
  416.   if (x1 > x2)
  417.   {
  418.     x1 ^= x2; x2 ^= x1; x1 ^= x2;
  419.   }
  420.   if ((x1 >= width) || (x2 < 0))
  421.     return;
  422.   if (x1 < 0) x1 = 0;
  423.   if (x2 >= width) x2 = width - 1;
  424.   if (c & 0x100)
  425.   {
  426.     register int cnt=x2-x1+1;
  427.     register unsigned char *ptr = data+x1+y*row_scale;
  428.     while(cnt--)
  429.       *ptr++ ^= c;
  430.   }
  431.   else
  432.     memset(data + x1 + y * row_scale, c, x2 - x1 + 1);
  433. }
  434.  
  435. void GrRegion::VLine(int x, int y1, int y2, int c)
  436. {
  437.   if (!data) return;
  438.   if (c == -1) c = color;
  439.   if ((x < 0) || (x >= width))
  440.     return;
  441.   if (y1 > y2)
  442.   {
  443.     y1 ^= y2; y2 ^= y1; y1 ^= y2;
  444.   }
  445.   if ((y1 >= height) || (y2 < 0))
  446.     return;
  447.   if (y1 < 0) y1 = 0;
  448.   if (y2 >= height) y2 = height-1;
  449.   register unsigned char *ptr = data + y1 * row_scale + x;
  450.   register int yc=y2-y1+1;
  451.   register int rs = row_scale;
  452.   if (c & 0x100)
  453.   {
  454.     for (; yc; yc--, ptr+=rs)
  455.       *ptr ^= c;
  456.   }
  457.   else
  458.   {
  459.     for (; yc; yc--, ptr+=rs)
  460.       *ptr = c;
  461.   }
  462. }
  463.  
  464. void GrRegion::Rectangle(int x1, int y1, int x2, int y2, int c)
  465. {
  466.   if (!data) return;
  467.   if (c == -1) c = color;
  468.   if (x1 > x2)
  469.   {
  470.     x1 ^= x2; x2 ^= x1; x1 ^= x2;
  471.   }
  472.   if (y1 > y2)
  473.   {
  474.     y1 ^= y2; y2 ^= y1; y1 ^= y2;
  475.   }
  476.   if ((x1 == x2) || (y1 == y2))
  477.   {
  478.     Line(x1, y1, x2, y2, c);
  479.     return;
  480.   }
  481.   Line(x1, y1, x2, y1, c);    // top
  482.   Line(x1, y1+1, x1, y2, c);    // left
  483.   Line(x2, y1+1, x2, y2, c);    // right
  484.   Line(x1+1, y2, x2-1, y2, c);    // botton
  485. }
  486.  
  487. void GrRegion::Box(int x, int y, int w, int h, int c)
  488. {
  489.   if (!data) return;
  490.   if (c == -1) c = color;
  491.   if (x < 0)
  492.   {
  493.     w += x;
  494.     x = 0;
  495.   }
  496.   if (y < 0)
  497.   {
  498.     h += y;
  499.     y = 0;
  500.   }
  501.   if (x > width)
  502.     return;
  503.   if (y > height)
  504.     return;
  505.   if (w > width)
  506.     w = width;
  507.   if (h > height)
  508.     h = height;
  509.   if ((w <= 0) || (h <= 0))
  510.     return;
  511.   if (c & 0x100)
  512.   {
  513.     while (h--)
  514.       HLine(x, x+w-1, y++, c);
  515.   }
  516.   else
  517.   {
  518.     while (h--)
  519.       memset(data+x+(y++)*row_scale, c, w);
  520.   }
  521. }
  522.  
  523. static unsigned char *fontptr=0;
  524.  
  525. extern "C" void int10(REGISTERS *);
  526.  
  527. void GrRegion::Text(int x, int y, char *text, int fgc, int bgc)
  528. {
  529.   if (!data) return;
  530.   if (fgc == -1) fgc = color;
  531.   if (!fontptr)
  532.   {
  533.     REGISTERS r;
  534.     r.ax = 0x1130;
  535. #define CHARHEIGHT 16 /* must correspond to value below */
  536.     r.bx = 0x0600;
  537.     int10(&r);
  538.     fontptr = (unsigned char *)r.bp;
  539.   }
  540.   int r, c, bits;
  541.   unsigned char *fp;
  542.   while (*text)
  543.   {
  544.     fp = fontptr + CHARHEIGHT * *(unsigned char *)text;
  545.     for (r=0; r<CHARHEIGHT; r++)
  546.     {
  547.       bits = *fp++;
  548.       for (c=0; c<8; c++)
  549.         if (bits & (0x80>>c))
  550.           Plot(x+c, y+r, fgc);
  551.         else if (bgc != -1)
  552.           Plot(x+c, y+r, bgc);
  553.     }
  554.     text++;
  555.     x += 8;
  556.   }
  557. }
  558.  
  559. int GrRegion::Point(int x, int y)
  560. {
  561.   if (!data) return 0;
  562.   if ((x < 0) || (y < 0) || (x >= width) || (y >= height))
  563.     return 0;
  564.   return data[x+y*row_scale];
  565. }
  566.